package com.nekonomics
package api

import com.nekonomics.error.{ParamError, TokenError}
import com.nekonomics.error.ParamError.{InvalidParam, ParamMissing}
import zio.ZIO
import zio.http.{Request, RoutePattern, Routes}
import zio.*
import zio.http.Header.Authorization
import zio.http.codec.PathCodec
import zio.json.*

package object route {
  trait ParamDecoder[T] {
    def decode(str: String): IO[Option[Nothing], T]
  }

  object ParamDecoder {

    given ParamDecoder[String] with
      def decode(str: String) = ZIO.succeed(str)

    given ParamDecoder[Long] with
      def decode(str: String) = ZIO.fromOption(str.toLongOption)

    given ParamDecoder[Int] with
      def decode(str: String) = ZIO.fromOption(str.toIntOption)

    given ParamDecoder[Boolean] with
      def decode(str: String) = ZIO.fromOption(str.toBooleanOption)
  }


  def extractParam[T: ParamDecoder](req: Request)(name: String): IO[ParamError, T] = {
    for {
      paramStr <- ZIO.succeed(req.url.queryParam(name)).someOrFail(ParamMissing(name))
      param <- summon[ParamDecoder[T]].decode(paramStr).mapError(_ => InvalidParam(s"$name 参数不合法"))
    } yield param
  }

  def extractJwt(req: Request): IO[TokenError, String] = {
    for {
      header <- ZIO.succeed(req.headers.header(Authorization)).someOrFail(TokenError.TokenMissing)
      str = header.renderedValue
      jwt <- ZIO.attempt(str.split(" ")(1)).mapError(_ => TokenError.InvalidToken())
    } yield jwt
  }


  def extractJsonBody[T: JsonDecoder](req: Request): ZIO[Any, ParamError, T] = {
    req.body.asString.map(_.fromJson[T]).right.mapError{ e =>
      ParamError.InvalidParam(e.swap.fold(_.getMessage, s => s))
    }
  }


  val baseApiPath: PathCodec[Unit] = PathCodec.literal("api")

}
